package com.jwsoft.manager.core.integration.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.IdcardUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.bifang.engine.assistant.core.annotation.ApiService;
import com.bifang.engine.assistant.core.annotation.OpApi;
import com.bifang.engine.assistant.core.annotation.SaveOplog;
import com.bifang.engine.assistant.core.enums.AuTypeEnum;
import com.bifang.engine.assistant.core.enums.BoolEnum;
import com.bifang.engine.assistant.core.enums.FuncTypeEnum;
import com.bifang.engine.assistant.core.exception.AppException;
import com.bifang.engine.assistant.core.utils.SessionUtil;
import com.bifang.engine.data.core.util.PagerUtil;
import com.bifang.module.base.common.util.ApplicationContextHelper;
import com.bifang.module.base.common.vo.dict.DictAreaVO;
import com.bifang.module.base.common.vo.dict.SelectVO;
import com.bifang.module.base.common.vo.excel.ExcelModelVO;
import com.bifang.module.base.common.vo.excel.ExcelReadVO;
import com.bifang.module.base.common.vo.excel.ExcelVO;
import com.bifang.module.base.common.vo.operationPeriod.OperationCurVO;
import com.bifang.module.base.common.vo.operationPeriod.OperationPeriodVO;
import com.bifang.module.base.core.helper.ApiContainer;
import com.bifang.module.base.core.helper.ApiModel;
import com.bifang.module.base.core.helper.DictHelper;
import com.bifang.module.base.core.helper.ExcelCommonHelper;
import com.bifang.module.base.core.integration.DictIntegration;
import com.bifang.module.base.core.integration.OperationPeriodIntegration;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.jwsoft.manager.common.enums.CardEnum;
import com.jwsoft.manager.common.vo.eduAppointStudent.EduAppointStudentKeyVO;
import com.jwsoft.manager.common.vo.eduAppointStudent.EduAppointStudentQueryVO;
import com.jwsoft.manager.common.vo.eduAppointStudent.EduAppointStudentVO;
import com.jwsoft.manager.common.vo.eduSchool.EduSchoolVO;
import com.jwsoft.manager.core.dao.model.EduAppointStudent;
import com.jwsoft.manager.core.dao.service.EduAppointStudentService;
import com.jwsoft.manager.core.dao.service.EduSchoolService;
import com.jwsoft.manager.core.integration.EduAppointStudentIntegration;
import com.jwsoft.manager.core.integration.OperationCacheIntegration;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.bifang.engine.assistant.core.utils.SessionUtil.getAreaCode;

/**
 * E类学籍名单维护表业务实现类
 *
 * @author wangtao
 * @since 2022-12-15
 */
@ApiService(funcCode = "eduAppointStudent", title = "E类学籍名单维护表")
public class EduAppointStudentIntegrationImpl implements EduAppointStudentIntegration {

    @Autowired
    public EduAppointStudentService eduAppointStudentService;

    @Autowired
    public EduStudentEnrollPreIntegrationImpl eduStudentEnrollPreIntegration;

    @Autowired
    ExcelCommonHelper excelCommonHelper;

    @Resource
    private ApiContainer apiContainer;

    @Resource
    OperationPeriodIntegration operationPeriodIntegration;

    @Autowired
    OperationCacheIntegration operationCacheIntegration;

    @Autowired
    public DictHelper dictHelper;

    @Autowired
    public EduSchoolService eduSchoolService;

    @Autowired
    private DictIntegration dictIntegration;
    @Override
    @OpApi(funcCode = "eduAppointStudent0001", title = "E类学籍名单维护表分页查询", funcType = FuncTypeEnum.query)
    public PageInfo<EduAppointStudentVO> getList(EduAppointStudentQueryVO vo) {
        // 开启分页
        if (vo.getPageNum() == null || vo.getPageSize() == null) {
            //如果不传入分页参数，默认最大取1000条
            vo.setPageNum(1);
            vo.setPageSize(1000);
        }
        PageHelper.startPage(vo.getPageNum(),vo.getPageSize());

        QueryWrapper<EduAppointStudent> appointStudentQueryWrapper = new QueryWrapper<>();
        if (vo.getYear() == null){
            Integer year = operationCacheIntegration.getPeriodYear().getYear();
            vo.setYear(year);
        }
        List<String> areaCodeList = new ArrayList<>();
        if (ObjectUtils.isEmpty(vo.getAreaCode())){
            List<SelectVO> selectVOList = dictIntegration.getDistrictByOrg(new DictAreaVO());
            areaCodeList = selectVOList.stream()
                    .map(SelectVO::getDictKey)
                    .collect(Collectors.toList());
        }else {
            areaCodeList.add(vo.getAreaCode());
        }
        if (CollectionUtils.isEmpty(areaCodeList)){
            throw new AppException("必须传入行政区划");
        }
        appointStudentQueryWrapper
                .lambda()
                .eq(
                        !ObjectUtils.isEmpty(vo.getSchoolId()),
                        EduAppointStudent::getSchoolId,
                        vo.getSchoolId())
                .eq(
                        !ObjectUtils.isEmpty(vo.getFullName()),
                        EduAppointStudent::getFullName,
                        vo.getFullName())
                .eq(
                        !ObjectUtils.isEmpty(vo.getIdcard()),
                        EduAppointStudent::getIdcard,
                        vo.getIdcard())
                .eq(vo.getYear() != null, EduAppointStudent::getYear, vo.getYear())
                .in(EduAppointStudent::getAreaCode,areaCodeList);

        List<EduAppointStudentVO> list = eduAppointStudentService.queryEStudentInfo(appointStudentQueryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            // 判断是否为空，为空则返回空参数
            return PagerUtil.createEmptyPagerInfo(vo.getPageNum(), vo.getPageSize());
        }
        // 不为空则获取分页结果
        PageInfo<EduAppointStudentVO> pageInfo = new PageInfo<>(list);
        // 返回参数需要通过common层的vo实体类，用该方法可以批量转换
        List<EduAppointStudentVO> resultList = Convert.toList(EduAppointStudentVO.class, pageInfo.getList());
        // 转义数据字典值
//         dictHelper.valueToName(resultList, Arrays.asList(DemoDictEnum.values()));
        return PagerUtil.parsePagerVo(resultList, pageInfo);
    }

    @Override
    @OpApi(funcCode = "eduAppointStudent0002", title = "E类学籍名单维护表根据主键查询详情", funcType = FuncTypeEnum.query)
    public EduAppointStudentVO getById(EduAppointStudentKeyVO vo) {
        EduAppointStudent entity = eduAppointStudentService.getById(vo.getAppointStudentId());
        if (ObjectUtils.isEmpty(entity)) {
            throw new AppException("查询不到详细信息!");
        }
        EduAppointStudentVO result = Convert.convert(EduAppointStudentVO.class, entity);
        dictHelper.valueToName(result, Arrays.asList(CardEnum.values()));

        return result;
    }
    /** 保存前统一校验*/
    @Override
    @OpApi(funcCode = "eduAppointStudent0003", title = "E类学籍名单维护表保存前校验", funcType = FuncTypeEnum.other ,checkPrivilege = BoolEnum.FALSE)
    public void checkSave(EduAppointStudentVO vo) {
        //主键为空为新增校验

        //主键不为空为修改校验


    }

    @Override
    @OpApi(funcCode = "eduAppointStudent0004", title = "E类学籍名单维护表新增", funcType = FuncTypeEnum.insert)
    @SaveOplog(
            operationType = "eduAppointStudent0004",
            operationName = "E类学籍名单维护表新增",
            dataType = "appointStudentId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public EduAppointStudentVO add(EduAppointStudentVO vo) {
        //保存前校验
        checkSave(vo);
        //身份证校验
        if (StringUtils.isBlank(vo.getSchoolId())){
            throw new AppException("未选择目标学校！");
        }
        if (StringUtils.isBlank(vo.getCardType())){
            throw new AppException("未选择证件类型！");
        }
        if (!IdcardUtil.isValidCard(vo.getIdcard()) && "01".equals(vo.getCardType())) {
            throw new AppException("学生身份证有误！");
        } else {
            vo.setIdcard(vo.getIdcard().trim().toUpperCase());
        }

        //做年份校验
        if(!operationCacheIntegration.getPeriodYear().getYear().equals(vo.getYear())){
            throw new AppException("只能添加当前学年的学生！");
        }

        //保存数据
        QueryWrapper<EduAppointStudent> appointStudentQueryWrapper = new QueryWrapper<>();
        appointStudentQueryWrapper
                .lambda()
                .eq(EduAppointStudent::getIdcard, vo.getIdcard())
                .eq(EduAppointStudent::getSchoolId,vo.getSchoolId())
                .eq(EduAppointStudent::getYear, vo.getYear());
        long count = eduAppointStudentService.count(appointStudentQueryWrapper);
        if (count > 0) {
            throw new AppException("该学生该年度已存在数据！");
        }
        EduAppointStudent appointStudent = new EduAppointStudent();
        appointStudent.setIdcard(StringUtils.upperCase(vo.getIdcard()));
        appointStudent.setFullName(vo.getFullName());
        appointStudent.setCardType(vo.getCardType());
        appointStudent.setSchoolId(vo.getSchoolId());
        appointStudent.setStatus(BoolEnum.TRUE.getType());
        appointStudent.setRemark(vo.getRemark());
        appointStudent.setAppointStudentId(IdUtil.simpleUUID());

        if(ObjectUtils.isEmpty(vo.getAreaCode())){
            vo.setAreaCode(getAreaCode());
        }
        appointStudent.setAreaCode(vo.getAreaCode());

        int year = 0;
        OperationCurVO curVO = new OperationCurVO();
        curVO.setOperating("XN");
        OperationPeriodVO operationPeriodVO =
                operationPeriodIntegration.getCurrentByOperating(curVO);
        if (operationPeriodVO != null) {
            year = operationPeriodVO.getPeriodYear();
        } else {
            year = DateUtil.thisYear();
        }
        appointStudent.setYear(year);
        eduAppointStudentService.save(appointStudent);
        //将主键设置回vo使操作日志可以取到
        vo.setAppointStudentId(appointStudent.getAppointStudentId());
        return vo;
    }

    @Override
    @OpApi(funcCode = "eduAppointStudent0005", title = "E类学籍名单维护表修改", funcType = FuncTypeEnum.update)
    @SaveOplog(
            operationType = "eduAppointStudent0005",
            operationName = "E类学籍名单维护表修改",
            dataType = "appointStudentId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public EduAppointStudentVO edit(EduAppointStudentVO vo) {
        if (ObjectUtils.isEmpty(vo.getAppointStudentId())) {
            throw new AppException("传入需要修改的主键不能为空!");
        }

        if (!IdcardUtil.isValidCard(vo.getIdcard()) && "01".equals(vo.getCardType())) {
            throw new AppException("学生身份证有误！");
        } else {
            vo.setIdcard(vo.getIdcard().trim().toUpperCase());
        }
        Integer year = operationCacheIntegration.getPeriodYear().getYear();
        if (!vo.getYear().equals(year)){
            throw new AppException("只能操作当前年份的信息!");
        }

        EduAppointStudent oldEntity = eduAppointStudentService.getById(vo.getAppointStudentId());
        if (!ObjectUtils.isEmpty(oldEntity)) {
            QueryWrapper<EduAppointStudent> appointStudentQueryWrapper = new QueryWrapper<>();
            appointStudentQueryWrapper
                    .lambda()
                    .eq(EduAppointStudent::getIdcard, vo.getIdcard())
                    .eq(EduAppointStudent::getYear, vo.getYear())
                    .ne(EduAppointStudent::getAppointStudentId, vo.getAppointStudentId());
            long count = eduAppointStudentService.count(appointStudentQueryWrapper);
            if (count > 0) {
                throw new AppException("该学生该年度已存在数据！");
            }
            BeanUtil.copyProperties(vo, oldEntity, CopyOptions.create().ignoreNullValue());
            eduAppointStudentService.saveOrUpdate(oldEntity);
        } else {
            throw new AppException("查询不到e类信息");
        }
        //保存前校验
        checkSave(vo);
        //保存数据
        return vo;
    }

    @Override
    @OpApi(funcCode = "eduAppointStudent0006", title = "E类学籍名单维护表根据主键删除", funcType = FuncTypeEnum.delete)
    @SaveOplog(
            operationType = "eduAppointStudent0006",
            operationName = "E类学籍名单维护表删除",
            dataType = "appointStudentId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public void del(EduAppointStudentKeyVO vo) {
        if (ObjectUtils.isEmpty(vo.getAppointStudentId())) {
            throw new AppException("传入需要删除的数据主键不能为空!");
        }
        EduAppointStudent entity = eduAppointStudentService.getById(vo.getAppointStudentId());
        if (ObjectUtils.isEmpty(entity)) {
            throw new AppException("未找到需要删除的信息!");
        }
        QueryWrapper<EduAppointStudent> eduAppointStudentQueryWrapper = new QueryWrapper<>();
        String year = String.valueOf(operationCacheIntegration.getPeriodYear().getYear());
        eduAppointStudentQueryWrapper
                .lambda().eq(EduAppointStudent::getAppointStudentId,vo.getAppointStudentId()).eq(EduAppointStudent::getYear,year);
        boolean remove = eduAppointStudentService.remove(eduAppointStudentQueryWrapper);
        if (!remove){
            throw new AppException("只能操作当前年份的信息!");
        }
    }
    @Override
    @OpApi(funcCode = "eduAppointStudent0007", title = "城区E类名单上传", funcType = FuncTypeEnum.insert)
    @SaveOplog(
            operationType = "eduAppointStudent0007",
            operationName = "城区E类名单上传",
            dataType = "studentEnrollPreId",
            auType = AuTypeEnum.OTHER)
    @Transactional
    public ExcelReadVO readExcel(ExcelVO vo, MultipartFile file,EduAppointStudentVO eduAppointStudentVO) {

        ExcelReadVO excelReadVO = new ExcelReadVO();
        excelReadVO.setCount(0);
        ExcelModelVO excelModelVO = eduStudentEnrollPreIntegration.getModel(vo);
        InputStream in = null;
        String schoolId = eduAppointStudentVO.getSchoolId();
        try {
            in = file.getInputStream();
            // File file2 = new File("C:\\Users\\Administrator\\Desktop\\工作簿1.xlsx");
            // in = new FileInputStream(file);
            if (StringUtils.isBlank(excelModelVO.getReadClass())) {
                List<Map<String, Object>> list = excelCommonHelper.readExcel(excelModelVO, in, true);

                List<Map<String, Object>> successList = new ArrayList<>();
                List<Map<String, Object>> errorList = new ArrayList<>();
                List<String> idcardList = new ArrayList<>();
                for (Map<String, Object> map : list) {
                    EduAppointStudentVO appointStudentVO = JSON.parseObject(JSON.toJSONString(map), EduAppointStudentVO.class);
                    if (appointStudentVO.getIdcard() == null || appointStudentVO.getFullName() == null) {
                        throw new AppException("模板有误!");
                    }
                    String remarks = "";
                    boolean flag = false;

                    if (StringUtils.isBlank(appointStudentVO.getIdcard())) {
                        remarks += "学生证件号码不能为空！";
                        flag = true;
                    } else {
                        appointStudentVO.setIdcard(appointStudentVO.getIdcard().trim().toUpperCase());
                    }

                    if (ObjectUtils.isEmpty(appointStudentVO.getFullName())) {
                        remarks += ("学生姓名不能为空！");
                        flag = true;
                    } else {
                        appointStudentVO.setFullName(
                                Validator.isChinese(appointStudentVO.getFullName())
                                        ? appointStudentVO.getFullName().replace(" ", "").trim()
                                        : appointStudentVO.getFullName().trim());
                    }
                    // 校验数据是否存在
                    int year = 0;
                    OperationCurVO curVO = new OperationCurVO();
                    curVO.setOperating("XN");
                    OperationPeriodVO operationPeriodVO =
                            operationPeriodIntegration.getCurrentByOperating(curVO);
                    if (operationPeriodVO != null) {
                        year = operationPeriodVO.getPeriodYear();
                    } else {
                        year = DateUtil.thisYear();
                    }
                    QueryWrapper<EduAppointStudent> appointStudentQueryWrapper =
                            new QueryWrapper<>();
                    appointStudentQueryWrapper
                            .lambda()
                            .eq(EduAppointStudent::getIdcard, appointStudentVO.getIdcard())
                            .eq(EduAppointStudent::getSchoolId,schoolId)
                            .eq(EduAppointStudent::getYear, year);
                    long count = eduAppointStudentService.count(appointStudentQueryWrapper);
                    if (count > 0) {
                       flag = true;
                       remarks = "该学生证件号码信息已存在";
                    }
                    if (flag) {
                        appointStudentVO.setRemark(remarks);
                        appointStudentVO.setYear(year);
                        errorList.add(JSON.parseObject(JSON.toJSONString(appointStudentVO), Map.class));
                    } else {
                        // 保存表信息
                        EduAppointStudent appointStudent = new EduAppointStudent();
                        appointStudent.setIdcard(StringUtils.upperCase(appointStudentVO.getIdcard()));
                        appointStudent.setFullName(appointStudentVO.getFullName());
                        appointStudent.setSchoolId(schoolId);
                        appointStudent.setAppointStudentId(IdUtil.simpleUUID());
                        appointStudent.setYear(year);
                        appointStudent.setStatus(BoolEnum.TRUE.getType());
                        if(ObjectUtils.isEmpty(eduAppointStudentVO.getAreaCode())){
                            eduAppointStudentVO.setAreaCode(getAreaCode());
                        }
                        appointStudent.setAreaCode(eduAppointStudentVO.getAreaCode());
                        eduAppointStudentService.save(appointStudent);
                        appointStudentVO.setAppointStudentId(appointStudent.getAppointStudentId());
                        appointStudentVO.setYear(year);
                        EduSchoolVO eduSchool = eduSchoolService.getDetail(schoolId);
                        if(eduSchool!=null){
                            appointStudentVO.setSchoolName(eduSchool.getSchoolName());
                        }
                        successList.add(JSON.parseObject(JSON.toJSONString(appointStudentVO), Map.class));
                    }

                }
                excelReadVO.setCount(successList.size() + errorList.size());
                excelReadVO.setSuccessCount(successList.size());
                excelReadVO.setSuccessList(successList);
                excelReadVO.setErrorList(errorList);
                excelReadVO.setErrorCount(errorList.size());




            }else {
                // 使用funcCode读取
                //本地接口
                ApiModel apiModel = apiContainer.get(excelModelVO.getReadClass());
                if (apiModel != null) {
                    Object bean = ApplicationContextHelper.getBean(apiModel.getBeanName());
                    if (null != bean) {
                        Object result = apiModel.getMethod().invoke(bean, vo, file);
                        return (ExcelReadVO) result;
                    }
                }
                //todo 微服务接口
            }
        } catch (AppException appEx) {
            throw appEx;
        } catch (IOException e) {
            throw new AppException("读取文件异常:" + e.getMessage());
        } catch (IllegalAccessException e) {
            throw new AppException("调用自定义读取服务异常:" + e.getMessage());
        } catch (InvocationTargetException e) {
            throw new AppException("调用自定义读取服务异常:" + e.getMessage());
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return excelReadVO;
    }

}
